use super::{get_cfg_file, json, Base, MapSv, RNull, Resp, SvCache, VBase, Value};
use base::file::JsonFile;

pub struct Fbf;

impl Base for Fbf {}

impl Fbf {
    pub fn get_file(&self, sub: &str, sn: &str, cache: &SvCache) -> Resp {
        let k_sn = self.get_key(sub, sn);

        match cache.get(&k_sn) {
            Some(v) => Ok(v),
            None => self.read_file(sub, sn),
        }
    }

    pub fn get_file_nocache(&self, sub: &str, sn: &str) -> Resp {
        self.read_file(sub, sn)
    }

    pub async fn remove(&self, sub: &str, sn: &str, cache: &SvCache) -> RNull {
        let k_sn = self.get_key(sub, sn);

        self.remove_file(sub, &sn)?;

        cache.invalidate(&k_sn).await;

        Ok(())
    }

    pub async fn write_nocache(&self, sub: &str, sn: &str, data: &Value) -> RNull {
        self.save_file(sub, &sn, data)?;
        Ok(())
    }

    pub async fn write(&self, sub: &str, sn: &str, data: &Value, cache: &SvCache) -> RNull {
        let k_sn = self.get_key(sub, sn);

        self.save_file(sub, &sn, data)?;

        cache.insert(k_sn, data.clone()).await;

        Ok(())
    }

    pub async fn update_file(&self, sub: &str, sn: &str, data: &Value, cache: &SvCache) -> RNull {
        let val = data.ckobj()?;
        let mut ret = MapSv::new();

        if let Ok(body) = self.read_file(sub, sn) {
            let body = body.ckobj()?;
            ret = body.clone();
        }

        for (k, v) in val.iter() {
            ret.insert(k.to_string(), v.clone());
        }

        let v = json!(ret);

        self.save_file(sub, sn, &v)?;

        let k_sn = self.get_key(sub, sn);
        cache.insert(k_sn, v.clone()).await;

        Ok(())
    }

    fn get_key(&self, sub: &str, k: &str) -> String {
        format!("{sub}{k}")
    }

    pub fn save_file(&self, sub: &str, k: &str, v: &Value) -> RNull {
        let p = get_cfg_file(sub, k);
        JsonFile::write_file(&p, v)
    }

    pub fn remove_file(&self, sub: &str, k: &str) -> RNull {
        let p = get_cfg_file(sub, k);
        JsonFile::del_file(&p)
    }

    pub fn is_exist(&self, sub: &str, k: &str) -> Result<bool, Value> {
        let p = get_cfg_file(sub, k);
        JsonFile::is_exist(&p)
    }

    pub fn read_file(&self, sub: &str, k: &str) -> Resp {
        let p = get_cfg_file(sub, k);
        JsonFile::read_file(&p)
    }
}
